<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\Plugin\Greeting\Listener;

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Utils\Codec\Json;
use MoChat\App\Corp\Utils\WeWorkFactory;
use MoChat\App\Medium\Constants\Type as MediumType;
use MoChat\App\Medium\Contract\MediumContract;
use MoChat\App\Utils\Media;
use MoChat\App\Utils\Url;
use MoChat\App\WorkContact\Contract\WorkContactContract;
use MoChat\App\WorkContact\Event\ContactWelcomeEvent;
use MoChat\Plugin\Greeting\Constants\RangeType;
use MoChat\Plugin\Greeting\Contract\GreetingContract;
use MoChat\Plugin\Lottery\Contract\LotteryContract;

/**
 * 添加企业客户事件.
 * 通用欢迎语执行优先级低一些，保障最后执行.
 *
 * @Listener(priority=1)
 */
class SendWelcomeListener implements ListenerInterface
{
    /**
     * @Inject
     * @var LotteryContract
     */
    protected $lotteryService;

    /**
     * @Inject
     * @var WorkContactContract
     */
    private $workContactService;

    /**
     * @Inject
     * @var GreetingContract
     */
    private $greetingService;

    /**
     * @Inject
     * @var MediumContract
     */
    private $mediumService;

    /**
     * @Inject
     * @var StdoutLoggerInterface
     */
    private $logger;

    public function listen(): array
    {
        return [
            ContactWelcomeEvent::class,
        ];
    }

    /**
     * @param ContactWelcomeEvent $event
     */
    public function process(object $event)
    {
        try {
            $contact = $event->message;

            // 判断是否需要发送欢迎语
            if (! $this->isNeedSendWelcome($contact)) {
                return;
            }

            // 获取欢迎语并发送
            $this->getWelcome($contact);
        } catch (\Throwable $e) {
            $this->logger->error(sprintf('[基础]客户欢迎语发送失败，错误信息: %s', $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
        }
    }

    /**
     * 判断是否需要发送欢迎语.
     *
     * @return bool
     */
    private function isNeedSendWelcome(array $contact)
    {
        // 已经发送过不再发送
        // 其他欢迎语可能会未设置或是不生效，也需要由通用欢迎语发送
        if ($this->workContactService->getWelcomeStatus((int) $contact['id']) === 1) {
            return false;
        }

        if (! isset($contact['welcomeCode']) || empty($contact['welcomeCode'])) {
            return false;
        }

        return true;
    }

    /**
     * 获取欢迎语.
     *
     * @param array $contact 客户
     */
    private function getWelcome(array $contact): array
    {
        $this->logger->error(sprintf('[基础]客户欢迎语匹配成功，触发，客户: %s', Json::encode($contact)));
        $data = [];
        $employeeId = $contact['employeeId'];
        $corpId = $contact['corpId'];
        if (empty($employeeId)) {
            return $data;
        }

        // 查询好友欢迎语
        $greetingList = $this->greetingService->getGreetingsByCorpId($corpId, ['id', 'medium_id', 'words', 'range_type', 'employees', 'span_welcome_status', 'span_welcome']);
        if (empty($greetingList)) {
            return $data;
        }
        $commonGreeting = [];
        foreach ($greetingList as $greeting) {
            // 检索通用欢迎语
            $greeting['rangeType'] === RangeType::ALL && $commonGreeting = $this->getGreeting($greeting);
            // 检索指定成员欢迎语
            $employees = empty($greeting['employees']) ? [] : Json::decode($greeting['employees']);
            if (! in_array($employeeId, $employees, true)) {
                continue;
            }
            $data = $this->getGreeting($greeting);
            if (! empty($data)) {
                break;
            }
        }

        if (empty($data) && ! empty($commonGreeting)) {
            $data = $commonGreeting;
        }

        if (empty($data)) {
            $this->logger->error(sprintf('[基础]客户欢迎语未发送，获取欢迎语为空，客户id: %s', (string) $contact['id']));
            return [];
        }

        $this->logger->error(sprintf('[基础]客户欢迎语匹配成功，即将发送，客户id: %s', (string) $contact['id']));
//        $this->workContactService->sendWelcome((int)$contact['corpId'], $contact, $contact['welcomeCode'], ['text'=>$data['text']]);
        if (isset($data['mediumId'])) {
            $medium = $this->getMedium($data['mediumId']);
            $this->logger->error(sprintf('[基础]客户欢迎语匹配成功，欢迎语，$medium: %s', Json::encode($medium)));
//            foreach ($medium as $item) {
//                $message['medium'] = $item;
//                $this->workContactService->sendWelcome((int)$contact['corpId'], $contact, $contact['welcomeCode'], $message);
//            }
            $medium[]['text'] = $data['text'];
            $weWorkContactApp = make(WeWorkFactory::class)->getContactApp($corpId);
            // 微信消息体
            $sendWelcomeData = $this->getSendWelcomeData($corpId, $contact, $medium);
            $sendWelcomeRes = $weWorkContactApp->external_contact_message->sendWelcome($contact['welcomeCode'], $sendWelcomeData);
            if ($sendWelcomeRes['errcode']!==0){
                $this->logger->error(sprintf('[基础]客户欢迎语匹配成功，发送错误，客户id: %s，错误信息：%s', (string) $contact['id'],$sendWelcomeRes['errmsg']));
            }
            unset($data['mediumId']);
        }
        return $data;
    }

    /**
     * 获取欢迎语结构体.
     */
    private function getSendWelcomeData(int $corpId, array $contact, array $media): array
    {
        $sendWelcomeData = [];
        foreach ($media as $content) {
            $content = $this->replaceContactName($content, $contact['name']);

            // 微信消息体 - 文本
            empty($content['text']) || $sendWelcomeData['text']['content'] = $content['text'];

            // 微信消息体 - 媒体文件
            if (! empty($content['mediumType'])) {
                $mediaUtil = make(Media::class);
                // 组织推送消息数据
                switch ($content['mediumType']) {
                    case MediumType::PICTURE:
                        // 上传临时素材
                        $image['msgtype'] = 'image';
                        $image['image']['media_id'] = $mediaUtil->uploadImage($corpId, $content['mediumContent']['imagePath']);
                        $sendWelcomeData['attachments'][] = $image;
                        break;
                    case MediumType::PICTURE_TEXT:
                        $link['msgtype'] = 'link';
                        $link['link'] = [
                            'title' => $content['mediumContent']['title'],
                            'url' => $content['mediumContent']['imageLink'],
                        ];

                        if (isset($content['mediumContent']['imagePath'])) {
                            $link['link']['picurl'] = file_full_url($content['mediumContent']['imagePath']);
                        }

                        if (isset($content['mediumContent']['description'])) {
                            $link['link']['desc'] = $content['mediumContent']['description'];
                        }
                        $sendWelcomeData['attachments'][] = $link;
                        break;
                    case MediumType::MINI_PROGRAM:
                        // 上传临时素材
                        $mediaId = $mediaUtil->uploadImage($corpId, $content['mediumContent']['imagePath']);
                        $miniprogram['msgtype'] = 'miniprogram';
                        $miniprogram['miniprogram'] = [
                            'title' => $content['mediumContent']['title'],
                            'pic_media_id' => $mediaId,
                            'appid' => $content['mediumContent']['appid'],
                            'page' => $content['mediumContent']['page'],
                        ];

                        $sendWelcomeData['attachments'][] = $miniprogram;
                        break;
                }
            }
        }

        return $sendWelcomeData;
    }

    /**
     * 替换内容中的客户名称.
     */
    private function replaceContactName(array $content, string $contactName): array
    {
        if (isset($content['text']) && ! empty($content['text'])) {
            $content['text'] = str_replace(['##客户名称##', '用户昵称'], [$contactName, $contactName], $content['text']);
        }

        return $content;
    }

    /**
     * @param string $mediumId 素材库ID
     * @return array 响应数组
     */
    private function getMedium($mediumId): array
    {
        $mediumContent = [];
        if (is_numeric($mediumId)) {
            $medium = $this->mediumService->getMediumById((int) $mediumId, ['id', 'type', 'content']);
            return empty($medium) ? [] : [[
                'mediumType' => $medium['type'],
                'mediumContent' => Json::decode($medium['content'], true),
            ]];
        }
        $mediums = $mediumId;
        is_array($mediums) || $mediums = Json::decode((string) $mediumId);
        foreach ($mediums as $mediumInfo) {
            if ((int) $mediumInfo['type'] === 1) {
                $medium = $this->mediumService->getMediumById($mediumInfo['id'], ['id', 'type', 'content']);
                if (empty($medium)) {
                    continue;
                }
                $mediumContent[] = [
                    'mediumType' => $medium['type'],
                    'mediumContent' => Json::decode($medium['content'], true),
                ];
            } elseif ((int) $mediumInfo['type'] === 2) {
                $lottery = $this->lotteryService->getLotteryById($mediumInfo['id'], ['id', 'name', 'description']);
                if (empty($lottery)) {
                    continue;
                }
                $link = [
                    'title' => $lottery['name'],
                    'description' => $lottery['description'],
                    'imagePath' => '2021/1227/1610/1640592639898161c974ffdb409.png',
                    'imageLink' => Url::getAuthRedirectUrl(2, $mediumInfo['id'], ['source' => 'from_pc']),
                ];
                $mediumContent[] = [
                    'mediumType' => 3,
                    'mediumContent' => $link,
                ];
            }
        }
        return $mediumContent;
    }

    private function getGreeting($greeting): array
    {
        // 分时段欢迎语开关-开启
        if ($greeting['spanWelcomeStatus'] === 1) {
            $spanWelcome = Json::decode($greeting['spanWelcome']);
            if (empty($spanWelcome)) {
                return [
                    'text' => $greeting['words'],
                    'mediumId' => $greeting['mediumId'],
                ];
            }
            foreach ($spanWelcome as $item) {
                // 判断是否在指定时间，指定星期内
                $time = date('H:i');
                if (isset($item['words'], $item['mediumId'], $item['startTime'], $item['endTime'], $item['week']) && $time > $item['startTime'] && $time < $item['endTime'] && in_array((int) date('w'), $item['week'], true)) {
                    return [
                        'text' => $item['words'],
                        'mediumId' => $item['mediumId'],
                    ];
                }
            }
        }
        return [
            'text' => $greeting['words'],
            'mediumId' => $greeting['mediumId'],
        ];
    }
}
